<?php

// TODO: events

// Zeus main class
final class Zeus
{

	/**
	 * Define run-param: Run
	 *
	 * @var int
	 */
	const ZEUS_RUN   = 0;

	/**
	 * Define run-param: Install
	 *
	 * @var int
	 */
	const ZEUS_INSTALL = 1;

	/**
	 * App object
	 *
	 * @var ZeusLib_Object
	 */
	private static $_app;

	/**
	 * Registry object
	 *
	 * @var ZeusLib_Object
	 */
	private static $_registry;

	/**
	 * Singleton array
	 *
	 * @var ZeusLib_Object
	 */
	private static $_singletons;


	/**
	 * Inizializes some essential stuff to work.
	 */
	public static function initalize()
	{
		// Create the registry object
		self::$_registry = array();

		// Create the singleton cache
		self::$_singletons = array();
	}

	/**
	 * Run Zeus
	 *
	 * Requires one of these inner run types:
	 * ZEUS_RUN
	 * ZEUS_INSTALL
	 *
	 * @param int type
	 */
	public static function run($type)
	{
		// Initialize some stuff
		self::initalize();

		// Get the app object
		$app = self::app();

		// Run the application
		$app->run($type);
	}

	/**
	 * Get the singleton app object
	 *
	 * @return Zeus_Core_Model_App
	 */
	public static function app()
	{
		// Return app singleton
		return self::getSingleton('core/app');
	}

	// TODO: comment
	public static function getSingleton($namespace, $args = null)
	{
		// Check whether the singleton exists
		if(!isset(self::$_singletons[$namespace]))
		{
			// Create a new model in the singleton cache
			self::$_singletons[$namespace] = self::getModel($namespace, $args);
		}

		// Return availible instance or new instance of the class
		return self::$_singletons[$namespace];
	}

	// TODO: use the config unique module index to resolve the correct classname!!
	// TODO: comment
	public static function getModel($namespace, $args = null)
	{
		// Get class name for namespace
		$classname = namespaceToClassname($namespace, 'model');

		// Check whether some args are given
		if($args !== null)
		{
			// Return new instace for the class with args
			return new $classname($args); // TODO: eval code for args array?
		}

		// Return new instace for the class without args
		return new $classname();
	}

	public static function getResourceModel()
	{
		throw new ToDo();
	}

	// TODO: comment
	public static function getView($namespace)
	{
		// Get class name for namespace
		$classname = namespaceToClassname($namespace, 'view');

		throw new ToDo();
	}

	/**
	 * Returns the xml object which was defined for that key in the xml structure.
	 *
	 * E.g. Zeus::getConfig('xmlnode1/xmlnode2/...')
	 * within the xmlnode1 is a root element of the xml structure.
	 *
	 * If the node does not exist, null is returned.
	 *
	 * @param string $key
	 * @return ZeusLib_Resource_Xml_Collection_Element|null
	 */
	public static function getConfig($key)
	{
		// TODO Here we could cache the config singleton
		// Return the application configuration
		return self::app()->getConfig()->getOption($key);
	}

	// TODO
	public static function getModuleConfig($key)
	{
		// Return the application configuration
		return self::app()->getConfig()->getModuleOption($key);
	}

	/**
	 * Puts and entry to the registry.
	 * This requires the a key and its value.
	 *
	 * @param string $key
	 * @param mixed $value
	 */
	public static function register($key, $value)
	{
		// Check whether the key exists
		if(isset(self::$_registry[$key]))
		{
			// Throw exception
			throw new Exception('Zeus registry key "'.$key.'" already exists.');
		}

		// Set the data
		self::$_registry[$key] = $value;
	}

	/**
	 * Removes an entry from the registry.
	 *
	 * @param string $key
	 */
	public static function unregister($key)
	{
		// Check whether the key exists
		if(isset(self::$_registry[$key]))
		{
			// Check whether the value is an object and a destruct method exists
			if(is_object(self::$_registry[$key]) && method_exists(self::$_registry[$key], '__destruct'))
			{
				// Destruct the object
				self::$_registry[$key]->__destruct();
			}

			// Delete the data
			unset(self::$_registry[$key]);
		}
	}

	/**
	 * Gets the data by the given key from the registry
	 *
	 * @param string $key
	 * @return mixed
	 */
	public static function registry($key)
	{
		// Check whether the key exists
		if(isset(self::$_registry[$key]))
		{
			// Return the data
			return self::$_registry[$key];
		}

		// Return null when the key not exists
		return null;
	}

}